import json
import random
from pathlib import Path
from dataclasses import dataclass
from typing import NamedTuple,Dict,Literal,Tuple,cast



class PunchProfile(NamedTuple):
    choices: int
    threshold: int
    hit_damage: int
    block_damage: int

    pre_msg: str
    hit_msg: str
    blocked_msg: str

    knockout_possible: bool = False


    def is_hit(self):
        return random.randint(1,self.choices) <= self.threshold
@dataclass
class Player:
        name: str
        best: int
        weakness: int
        HP: int
        initial_hp: int
        #可以通过is_computer判断是玩家还是电脑
        is_computer: bool
        punch_profiles: Dict[Literal[1,2,3,4],PunchProfile]
        damage: int = 0
        score: int = 0
        knockedout:bool=False

        def get_punch_choice(self) -> Literal [1,2,3,4]:
            #生成电脑的拳法通过随机数
            if self.is_computer:
                return  random.randint(1,4)
            else:   punch = -1
        #通过while死循环要求玩家必须选择1-4中一个数字
            while punch not in [1,2,3,4,]:
                print(f"{self.name}的招式是?")
                punch = int(input())
                if punch not in [1,2,3,4,]:
                    print("请玩家重新选择拳击信息：")
                    punch = int(input())
                return punch
#击倒阈值
KNOCKOUT_THRESHOLD = 50
#击晕信息
KNOCKOUT_COLD = "{loser}被击晕了无法正常比赛，胜利属于{winner}"

#获取选手弱点信息
def get_vulnerability(player_best):
    print("请选择玩家的弱点是：")
    #对于数字的判断
    vulnerability=int(input())
    if vulnerability not in [1,2,3,4]:
        if vulnerability == player_best:
            print("请不要破坏规则，重新输入！")
            vulnerability=int(input())
    return vulnerability
#获取电脑弱点信息
def get_opponent_stats() -> Tuple[int,int]:
    opponent_best = 0
    opponent_weakness = 0
    while opponent_best==opponent_weakness:
        opponent_best = random.randint(1,4)
        opponent_weakness = random.randint(1,4)
        return opponent_best,opponent_weakness

    #获取招式基本信息
def read_punch_profiles(filepath: Path):
        with open(filepath,encoding='utf-8') as f:
            punch_profile_dict = json.load(f)
        return  {
            cast(Literal[1,2,3,4],int(key)):PunchProfile(**value)
            for key,value in punch_profile_dict.items()
        }

def main() ->None:
    print("拳击游戏")
    print("desgin by zct")
    print("由zct设计创建")
    print("202312060341")
    print("---------------------------")
    print("这个游戏采取奥运规则，三局两胜")
    print("期待你通过策略与运气赢得比赛！")
    print("玩家名字为：")
    player_name = input()
    print("对手名字为：")
    opponent_name=input()

    print("不同的出拳策略 1.摆拳 2.平勾拳 3.上钩拳 4.刺拳 ")
    print("从1-4选项中请选择玩家擅长的招式：")
    player_best = int(input())
    while player_best not in [1,2,3,4]:
        print("请选择正确的选项!")
        player_best = int(input())
    player_weakness = get_vulnerability(player_best)
    player=Player(
        name = player_name,
        best = player_best,
        weakness = player_weakness,
        HP = random.randint(100, 120),
        initial_hp=0,
        is_computer = False,

        punch_profiles=read_punch_profiles(
            Path(__file__).parent/"player-profile.json"
        ),
    )

    opponent_best,opponent_weakness=get_opponent_stats()
    opponent = Player(
        name=opponent_name,
        best=opponent_best,
        weakness=opponent_weakness,
        HP=random.randint(100, 120),
        initial_hp=0,
        is_computer=True,
        punch_profiles=read_punch_profiles(
            Path(__file__).parent /"opponent-profile.json"
        ),
    )
    #做一次判断看能不能读取对应文件数据
    print(player)
    print(opponent)
    opponent.initial_hp=opponent.HP
    player.initial_hp=player.HP

    print("比赛正式开始，请做好准备！")
    for round_number in (1,2,3):
        if player.knockedout or opponent.knockedout:
            break
        play_round(round_number,player,opponent)

    if player.knockedout:
        print(KNOCKOUT_COLD.format(loser=player.name,winner=opponent.name))
    elif opponent.knockedout:
        print(KNOCKOUT_COLD.format(loser=opponent.name,winner=player.name))
    elif opponent.score > player.score:
        print(f"{opponent.name}打败了{player.name}")
    else:
        print(f"{player.name}打败了{opponent.name}")

    print("\n\n比赛结束")
    print("感谢游玩")

#生成1个1-10的随机数，如果数字大于5则是对面回合
def is_opponents_turn() ->bool:
    return random.randint(1,10)>5

def play_round(round_number: int, player: Player, opponent:Player) ->None:
    print(f"    第{round_number}轮次\n-----开始------\n")

    if round_number==1:
        print(f"这一轮{player.name} 初始血条为{player.HP}")
        print(f"这一轮{opponent.name} 初始血条为{opponent.HP}")
    else:
        player.HP=player.initial_hp
        opponent.HP=opponent.initial_hp
        print(f"{player.name} 初始血条为{player.HP}")
        print(f"{opponent.name} 初始血条为{opponent.HP}")
    #三局两胜的规则，如果有一方的分数>=2，则直接结束
    if opponent.score>=2 or player.score>=2:
        return

    for _action in range(7):
        # 不用再区分是玩家攻击还是电脑攻击，只做谁主动谁被动的判断
        print("-----------------------------")
        if is_opponents_turn():
            punch = opponent.get_punch_choice()
            active = opponent
            passive = player
            opponents_turn = True
        else:
            punch = player.get_punch_choice()
            active = player
            passive = opponent
            opponents_turn = False
        punch_profile = active.punch_profiles[punch]
        print(punch_profile.pre_msg.format(opponent=opponent,player=player))
        #如果选中的招式是擅长的招式则攻击+2
        if punch == active.best:
            active.damage = active.damage+2

        #如果对手不擅长这个招数，那么他将总是被击中
        if passive.weakness == punch or punch_profile.is_hit():
            print(punch_profile.hit_msg.format(opponent=opponent,player=player))
            #判定是否存在直接击倒的可能性
            if punch_profile.knockout_possible and active.damage>KNOCKOUT_THRESHOLD:
                if opponents_turn and opponent.damage>KNOCKOUT_THRESHOLD and opponent.HP != 0:
                    player.knockedout = True
                    player.HP=0
                    print(f"哦，不，看啊！！！{player.name}被击晕了，血条值骤减为{player.HP}")
                    break
                elif opponents_turn ==False and player.damage>KNOCKOUT_THRESHOLD and player.HP !=0:
                    opponent.knockedout = True
                    opponent.HP = 0
                    print(f"哦，不，看啊！！！{opponent.name}被击晕了，血条值骤减为{opponent.HP}")
                    break
            #如果不存在击倒可能性则记录伤害
            if opponents_turn == True:
                opponent.damage = opponent.damage+punch_profile.hit_damage
                if player.HP <= 0:
                    player.HP=0
                    print(f"{player.name}的血条为{player.HP}, {player.name}不再有战斗的能力")
                else:
                    player.HP = player.HP - opponent.damage
                    print(f"{player.name}受伤了，血条值下降为{player.HP}")
            else:
                player.damage += punch_profile.hit_damage
                if opponent.HP <= 0:
                    opponent.HP=0
                    print(f"{opponent.name}的血条为{opponent.HP}, {opponent.name}不再有战斗的能力")
                else:
                    opponent.HP = opponent.HP - player.damage
                    print(f"{opponent.name}受伤了，血条值下降为{opponent.HP}")

        else:
            print(punch_profile.blocked_msg.format(opponent=opponent,player=player))
            #如果对面闪开了你的攻击，可能会因为你的攻击后摇太大对你造成反击
            if opponents_turn:
                player.damage +=punch_profile.block_damage
                player.HP = player.HP - player.damage
                print(f"{player.name}挡住了攻击，因为格挡血条值下降为{player.HP}")
            else:
                opponent.damage +=punch_profile.block_damage
                opponent.HP = opponent.HP - opponent.damage
                print(f"{opponent.name}挡住了攻击，因为格挡血条值下降为{opponent.HP}")
        #如果有人被击晕，直接结束比赛
        if player.knockedout or opponent.knockedout:
            break
        if player.HP == 0:
            print(f"{player.HP}血条为0，显而易见这局{player.HP}已经没有比赛能力了")
            break
        elif opponent.HP == 0:
            print(f"{opponent.HP}血条为0，显而易见这局{opponent.HP}已经没有比赛能力了")
            break
    #这里的分数用伤害统计，不太合理并且每一局的伤害会累计到下一局，也就是说如果你第一局造成大量伤害，第二局没造成伤害也有可能获胜
    if player.damage > opponent.damage:
        print(f"{player.name}获得了第{round_number}场胜利")
    else:
        print(f"{opponent.name}获得了第{round_number}场胜利")

if __name__ == "__main__":
    main()
